package com.ld.shieldsb.dao;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

import org.apache.commons.dbutils.BeanProcessor;
import org.apache.commons.lang.StringUtils;

import com.ld.shieldsb.annotation.field.Mask;
import com.ld.shieldsb.annotation.mask.Masker;
import com.ld.shieldsb.annotation.mask.Type;
import com.ld.shieldsb.annotation.mask.impl.IdCardMasker;
import com.ld.shieldsb.annotation.mask.impl.PhoneMasker;
import com.ld.shieldsb.annotation.util.AnnotationUtil;
import com.ld.shieldsb.common.core.reflect.ModelUtil;
import com.ld.shieldsb.common.core.util.date.DateTimeUtil;
import com.ld.shieldsb.dao.util.ContextUtil;

import lombok.extern.slf4j.Slf4j;

/**
 * 
 * 基础javaBean相关
 * 
 * @ClassName MyBeanProcessor
 * @author <a href="mailto:donggongai@126.com" target="_blank">kevin</a>
 * @date 2016年8月25日 下午2:25:01
 *
 */
@Slf4j
public class MyBeanProcessor extends BeanProcessor {

    @Override
    public <T> T toBean(ResultSet rs, Class<T> modelType) throws SQLException {
        try {
            T t = modelType.newInstance();
            Map<String, Field> fieldMap = AnnotationUtil.getFieldMap(modelType);
            return type2Bean(rs, t, fieldMap);
        } catch (Exception e) {
            log.error("", e);
        }
        return null;
    }

    @Override
    public <T> List<T> toBeanList(ResultSet rs, Class<T> modelType) throws SQLException {
        List<T> results = new ArrayList<>();
        try {
            Map<String, Field> fieldMap = null;
            while (rs.next()) {
                try {
                    if (fieldMap == null) {
                        fieldMap = AnnotationUtil.getFieldMap(modelType);
                    }
                    T t = modelType.newInstance();
                    results.add(type2Bean(rs, t, fieldMap));
                } catch (Exception e) {
                    log.error("", e);
                }
            }
        } catch (Exception e) {
            log.error("", e);
        }
        return results;
    }

    /**
     * 将DAO的RS结果集转换为bean对象
     * 
     * @Title type2Bean
     * @author 吕凯
     * @date 2017年5月20日 上午8:39:44
     * @param <T>
     * @param rs
     * @param model
     * @param fieldMap
     * @return
     * @throws SQLException
     * @throws InstantiationException
     * @throws IllegalAccessException
     * @throws IllegalArgumentException
     * @throws InvocationTargetException
     *             T
     */
    private <T> T type2Bean(ResultSet rs, T model, Map<String, Field> fieldMap)
            throws SQLException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        ResultSetMetaData meta = rs.getMetaData();
        int cols = meta.getColumnCount() + 1;
        for (int i = 1; i < cols; i++) {
            String colName = meta.getColumnLabel(i).toLowerCase();
            Field field = fieldMap.get(colName);
            if (field != null) {
                field.setAccessible(true);
                Class<?> fieldType = field.getType();
                Object value = rs.getObject(i);
                try {
                    if (value == null) {
                    } else if (value != null && fieldType.equals(Date.class)) {
                        if (value.getClass().equals(String.class)) {
                            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                            try {
                                field.set(model, sdf.parse((String) value));
                            } catch (ParseException e) {
                                log.error("日期字段读取失败," + fieldType + ",error:" + e.getMessage());
                            }
                        } else if (value.getClass().equals(LocalDateTime.class)) {
                            field.set(model, DateTimeUtil.localDateTime2Date((LocalDateTime) value));
                        } else if (value.getClass().equals(LocalDate.class)) {
                            field.set(model, DateTimeUtil.localDate2Date((LocalDate) value));
                        } else {
                            field.set(model, value);
                        }
                    } else if (fieldType.equals(int.class) || fieldType.equals(Integer.class)) {
                        field.set(model, rs.getInt(i));
                    } else if (fieldType.equals(long.class) || fieldType.equals(Long.class)) {
                        field.set(model, rs.getLong(i));
                    } else if (fieldType.equals(float.class) || fieldType.equals(Float.class)) {
                        field.set(model, rs.getFloat(i));
                    } else if (fieldType.equals(double.class) || fieldType.equals(Double.class)) {
                        field.set(model, rs.getDouble(i));
                    } else {
                        if (value instanceof Clob) { // clob特殊处理
                            String clobValue = ClobToString((Clob) value);
                            // log.info(colName + " " + clobValue);
                            field.set(model, clobValue);
                        } else if (value instanceof Blob) { // blob特殊处理
                            byte[] blobValue = blob2ByteArr((Blob) value);
                            // log.info(colName + " " + clobValue);
                            if (fieldType.equals(String.class)) {
                                field.set(model, new String(blobValue));
                            } else {
                                field.set(model, blobValue);
                            }
                        } else if (fieldType.equals(String.class)) {
                            String strValue = value.toString();
                            if (ContextUtil.Set.MASK && field.isAnnotationPresent(Mask.class) && StringUtils.isNotBlank(strValue)) { // 需要脱敏
                                Mask maskAnno = field.getAnnotation(Mask.class);
                                if (maskAnno.value()) { // 需要脱敏
                                    if (maskAnno.masker() != Masker.class) {
                                        Masker masker = ContextUtil.getMasker(maskAnno.masker());
                                        strValue = masker.mask(strValue);
                                    } else if (maskAnno.type() != Type.NULL) {
                                        Type type = maskAnno.type();
                                        Masker masker = null;
                                        if (type == Type.ID_CARD) { // 身份证
                                            masker = ContextUtil.getMasker(IdCardMasker.class);
                                        } else if (type == Type.PHONE) { // 手机号
                                            masker = ContextUtil.getMasker(PhoneMasker.class);
                                        }
                                        if (masker != null) { // 存放原始值
                                            if (ModelUtil.hasField(model, field.getName() + "Src")) {
                                                ModelUtil.setModelValue(model, field.getName() + "Src", strValue);
                                            }
                                            strValue = masker.mask(strValue);
                                        }
                                    }
                                }
                            }
                            field.set(model, strValue);
                        } else {
                            field.set(model, value);
                        }
                    }
                } catch (Exception e) {
                    log.error("fieldType:" + fieldType + ",fieldName:" + colName + ",value:" + value + "," + e.getMessage());
                }
            } else {
                // log.info(model.getClass() + "中缺少对应属性---数据库列名:" + colName);
            }
        }
        // TODO 暂不开启查询confirm，防止查询后更新操作出错
//        DAOModelUtil.confirmValues(model);
        return model;
    }

    /**
     * 
     * COLB类型转成String
     * 
     * @Title ClobToString
     * @param clob
     *            colb字段
     * @return String
     */
    public String ClobToString(Clob clob) {
        String reString = "";
        Reader is = null;
        try {
            is = clob.getCharacterStream();
            // 得到流
            BufferedReader br = new BufferedReader(is);
            String s = null;
            try {
                s = br.readLine();
            } catch (IOException e) {
                log.error("", e);
            }
            StringBuffer sb = new StringBuffer();
            while (s != null) {
                // 执行循环将字符串全部取出付值给StringBuffer由StringBuffer转成STRING
                sb.append(s);
                try {
                    s = br.readLine();
                } catch (IOException e) {
                    log.error("", e);
                }
            }
            reString = sb.toString();
        } catch (SQLException e) {
            log.error("", e);
        }
        return reString;
    }

    /**
     * blob转字节数组
     * 
     * @Title blob2ByteArr
     * @author 吕凯
     * @date 2017年5月20日 上午8:40:40
     * @param blob
     * @return
     * @throws Exception
     *             byte[]
     */
    public byte[] blob2ByteArr(Blob blob) throws Exception {
        BufferedInputStream is = null;
        byte[] bytes = null;
        try {
            is = new BufferedInputStream(blob.getBinaryStream());
            bytes = new byte[(int) blob.length()];
            int len = bytes.length;
            int offset = 0;
            int read = 0;

            while (offset < len && (read = is.read(bytes, offset, len - offset)) >= 0) {
                offset += read;
            }

        } catch (Exception e) {
            log.error("", e);
        }
        return bytes;
        // byte[] b = null;
        // try {
        // if (blob != null) {
        // long in = 0;
        // b = blob.getBytes(in, (int) (blob.length()));
        // }
        // } catch (Exception e) {
        // e.printStackTrace();
        // }
        //
        // return b;
    }

    public static void main(String[] args) {
        System.out.println(int.class);
        System.out.println(Integer.class);
    }

}
